using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Net;
using System.Diagnostics;
using System.Threading;
using System.DirectoryServices;
using PSLib = Microsoft.Office.Project.Server.Library;

namespace DataPopulation
{
    class Helper
    {
        #region Private Data
        private static wsCalendar.CalendarDataSet dsCalendar;
        private static wsResource.ResourceDataSet dsResource;
        private static wsLookup.LookupTableDataSet dsLookup;
        private static wsCustomFields.CustomFieldDataSet dsProjCustomFields;
        private static wsCustomFields.CustomFieldDataSet dsTaskCustomFields;
        private static wsCustomFields.CustomFieldDataSet dsResCustomFields;

        private static Random rnd = new Random(117);
        private static MainForm main;
        #endregion

        #region Constructors
        private Helper()
        {
        }

        public Helper(MainForm mainForm)
        {
            main = mainForm;
        }
        #endregion

        #region Load Data
        static public void LoadDataCache()
        {
            dsProjCustomFields = customFields.ReadCustomFieldsByEntity(new Guid(PSLib.EntityCollection.Entities.ProjectEntity.UniqueId));
            dsTaskCustomFields = customFields.ReadCustomFieldsByEntity(new Guid(PSLib.EntityCollection.Entities.TaskEntity.UniqueId));
            dsResCustomFields = customFields.ReadCustomFieldsByEntity(new Guid(PSLib.EntityCollection.Entities.ResourceEntity.UniqueId));
            dsLookup = lookup.ReadLookupTables("", false, 1033);
            dsCalendar = ReadCalendars();
        }
        #endregion

        #region Processing Methods
        public void CreateResources()
        {
            try
            {
                CreateResourcesItem queueItem = WorkQueues.qCreateResources.DequeueItem();

                // Setup the new resource and the security groups and categories.
                dsResource = resource.ReadResources("", false);
                wsResource.ResourceDataSet dsNewResources = new wsResource.ResourceDataSet();
                wsResource.ResourceAuthorizationDataSet dsAuth = new wsResource.ResourceAuthorizationDataSet();

                string resName = "";
                string digits = "";
                for (int resNum = queueItem.start; resNum <= queueItem.end; resNum++)
                {
                    digits = GetDigits(resNum, queueItem.numDigits);
                    // Build the resource name.
                    resName = queueItem.resPrefix + digits;

                    // Build the nt acct name.
                    if (queueItem.createLogins && queueItem.ntAuth)
                    {
                        SetStatus("Adding NT account " + resName + ".", true);
                        try
                        {
                            AddUser(queueItem.domain, resName, queueItem.password);
                        }
                        catch (Exception ex)
                        {
                            SetStatus("User account " + resName + " not added.  " + ex.Message, false);
                        }
                    }

                    wsResource.ResourceDataSet.ResourcesRow rowResource = AddResource(resName, resName, dsNewResources, dsAuth, queueItem.ntAuth, queueItem.domain);
                    AddSecurityGroups(dsAuth, rowResource, queueItem.securityGroups);
                    AddSecurityCategories(dsAuth, rowResource, queueItem.securityCategories);

                    if (queueItem.createCFs) AddResCFs(rowResource.RES_UID, dsNewResources.ResourceCustomFields, queueItem.leafsOnly);
                }

                // Create the resource.
                SetStatus("Creating resources.", true);
                try
                {
                    resource.CreateResources(dsNewResources, false, true);
                }
                catch (Exception ex)
                {
                    SetStatus("CreateResources failed. " + ex.Message, false);
                    return;
                }
                SetStatus("Setting authorization.", true);
                try
                {
                    resource.SetResourceAuthorization(dsAuth);
                }
                catch (Exception ex)
                {
                    SetStatus("SetResourceAuthorization failed. " + ex.Message, false);
                    return;
                }
                SetStatus("Resource creation completed.", true);
            }
            catch (Exception ex)
            {
                SetStatus(ex.Message, false);
            }
        }

        public void CreateProjects()
        {
            try
            {
                CreateProjectsItem queueItem = WorkQueues.qCreateProjects.DequeueItem();

                int count = 0;

                // Loop for the number of projects.
                string digits;
                Guid projGuid;
                wsProject.ProjectTeamDataSet dsTeam = new wsProject.ProjectTeamDataSet();
                dsResource = resource.ReadResources("", false);
                SetStatus(queueItem.projectEnd - queueItem.projectStart + 1 + " projects matched.", true);
                for (int projCount = queueItem.projectStart; projCount <= queueItem.projectEnd; projCount++)
                {
                    wsProject.ProjectDataSet dsProject = new wsProject.ProjectDataSet();

                    digits = GetDigits(projCount, queueItem.projectNumDigits);
                    string projectName = queueItem.projectPrefix + digits;

                    // Check if using project template.
                    if (queueItem.projectType == "Template")
                    {
                        try
                        {
                            project.CreateProjectFromTemplate(queueItem.template, projectName);
                            SetStatus("Project " + projectName + " queued for creation.", true);
                        }
                        catch (Exception ex)
                        {
                            SetStatus("CreateProjectFromTemplate failed for project " + projectName + ". " + ex.Message, false);
                        }
                        continue;
                    }

                    // Add the project to the dataset.
                    projGuid = CreateProject(dsProject, projectName, queueItem.projectType.ToString(), queueItem.ownerPrefix, queueItem.ownerNumDigits, queueItem.ownerEnd, queueItem.ownerStart, queueItem.calendarType);
                    SetStatus("Adding project " + projectName + ".", true);
                    if (queueItem.createCFs) AddProjCFs(projGuid, dsProject.ProjectCustomFields, queueItem.leafsOnly);

                    // Create the project.
                    Guid jobGuid = Guid.NewGuid();
                    SetStatus("Creating project " + projectName + ".", true);
                    try
                    {
                        project.QueueCreateProject(jobGuid, dsProject, false);
                        SetStatus("Project " + projectName + " queued for creation.", true);
                    }
                    catch (Exception ex)
                    {
                        SetStatus("QueueCreateProject failed for project " + projectName + ". " + ex.Message, false);
                        continue;
                    }
                    count++;
                }
                SetStatus("Project creation completed.", true);
            }
            catch (Exception ex)
            {
                SetStatus(ex.Message, false);
            }
        }

        public void CreateTasks()
        {
            try
            {
                CreateTasksItem queueItem = WorkQueues.qCreateTasks.DequeueItem();

                int count = 0;
                string digits;
                Guid taskGuid;
                Guid projGuid;
                string projName;

                wsProject.ProjectDataSet dsProject = new wsProject.ProjectDataSet();
                wsProject.ProjectDataSet dsUpdateProject = new wsProject.ProjectDataSet();
                wsProject.ProjectDataSet dsProjects = project.ReadProjectStatus(Guid.Empty, wsProject.DataStoreEnum.WorkingStore, "", (int)PSLib.Project.ProjectType.Project);
                if (dsProjects == null)
                {
                    SetStatus("ReadProjectStatus failed in Create Tasks.", false);
                    return;
                }

                // Sort and filter the projects by name.
                dsProjects.Project.DefaultView.RowFilter = "PROJ_NAME like '" + queueItem.projectPrefix + "%'";
                dsProjects.Project.DefaultView.Sort = "PROJ_NAME";

                foreach (DataRowView rowProject in dsProjects.Project.DefaultView)
                {
                    projGuid = (Guid)rowProject["PROJ_UID"];
                    projName = rowProject["PROJ_NAME"].ToString();

                    dsProject = project.ReadProject(projGuid, wsProject.DataStoreEnum.WorkingStore);
                    if (dsProject == null)
                    {
                        SetStatus("ReadProject failed for project " + projName + ".", false);
                        continue;
                    }
                    SetStatus("Project " + projName + " has " + dsProject.Task.Rows.Count + " tasks.", true);
                    if (dsProject.Task.Rows.Count >= queueItem.tasksPerProject)
                    {
                        SetStatus("Project " + projName + " skipped.", true);
                        continue;
                    }

                    Guid sessionGuid = Guid.NewGuid();
                    bool ok = CheckOutProject(projGuid, sessionGuid, projName);
                    if (!ok) continue;

                    // Add tasks to the project.
                    // Break the operation up into manageable entity chunks.
                    try
                    {
                        int maxEntities = queueItem.entityLimit;
                        int numTasks = 0;
                        for (int taskCount = 1; taskCount <= queueItem.tasksPerProject - dsProject.Task.Rows.Count; taskCount++)
                        {
                            digits = GetDigits(taskCount, queueItem.numDigits);
                            string taskName = queueItem.taskPrefix + digits;
                            taskGuid = CreateTask(dsUpdateProject, projGuid, taskName, false, queueItem.maxDuration, queueItem.minDuration);
                            if (queueItem.createCFs) AddTaskCFs(projGuid, taskGuid, dsUpdateProject.TaskCustomFields, dsUpdateProject.TaskCustomFields, queueItem.leafsOnly);
                            numTasks++;

                            // Update the project.
                            if (numTasks >= maxEntities)
                            {
                                AddToProject(sessionGuid, projName, dsUpdateProject, "Added " + numTasks.ToString() + " tasks to project " + projName + ".");
                                dsUpdateProject.Task.Clear();
                                dsUpdateProject.TaskCustomFields.Clear();
                                numTasks = 0;
                            }
                        }
                        // Final update.
                        if (numTasks > 0)
                        {
                            AddToProject(sessionGuid, projName, dsUpdateProject, "Added " + numTasks.ToString() + " tasks to project " + projName + ".");
                            dsUpdateProject.Task.Clear();
                            dsUpdateProject.TaskCustomFields.Clear();
                        }
                    }
                    catch (Exception ex)
                    {
                        SetStatus("Adding tasks failed for project " + projName + ". " + ex.Message, false);
                    }

                    CheckInProject(projGuid, sessionGuid, projName, false);

                    count++;
                }
                SetStatus("Task creation completed.", true);
            }
            catch (Exception ex)
            {
                SetStatus(ex.Message, false);
            }
        }

        public void CreateCFs()
        {
            try
            {
                CreateCFsItem queueItem = WorkQueues.qCreateCFs.DequeueItem();

                int count = 0;
                const int PROJECT_FIELDS = 1;
                const int TASK_FIELDS = 2;
                const int TASK_CUSTOM_FIELDS = 64;
                if (queueItem.createProjectCFs || queueItem.createTaskCFs)
                {
                    Guid projGuid;
                    string projName;
                    int numTaskCFs = Helper.GetNumTaskCFs;

                    wsProject.ProjectDataSet dsProject = new wsProject.ProjectDataSet();
                    wsProject.ProjectDataSet dsProjectUpdate = new wsProject.ProjectDataSet();
                    wsProject.ProjectDataSet dsProjects = project.ReadProjectStatus(Guid.Empty, wsProject.DataStoreEnum.WorkingStore, "", (int)PSLib.Project.ProjectType.Project);
                    if (dsProjects == null)
                    {
                        SetStatus("ReadProjectStatus failed in Create Custom Fields.", false);
                        return;
                    }

                    // Sort and filter the projects by name.
                    dsProjects.Project.DefaultView.RowFilter = "PROJ_NAME like '" + queueItem.projectPrefix + "%'";
                    dsProjects.Project.DefaultView.Sort = "PROJ_NAME";

                    foreach (DataRowView rowProject in dsProjects.Project.DefaultView)
                    {
                        projGuid = (Guid)rowProject["PROJ_UID"];
                        projName = rowProject["PROJ_NAME"].ToString();
                        dsProject = project.ReadProjectEntities(projGuid, PROJECT_FIELDS | TASK_FIELDS | TASK_CUSTOM_FIELDS, wsProject.DataStoreEnum.WorkingStore);
                        if (dsProject == null)
                        {
                            SetStatus("ReadProject failed for project " + projName + ".", false);
                            continue;
                        }

                        Guid sessionGuid = Guid.NewGuid();
                        bool ok = CheckOutProject(projGuid, sessionGuid, projName);
                        if (!ok) continue;

                        try
                        {
                            if (queueItem.createProjectCFs) AddProjCFs(projGuid, dsProject.ProjectCustomFields, queueItem.projectLeafsOnly);
                            if (queueItem.createTaskCFs)
                            {
                                foreach (DataRow dr in dsProject.Task.Rows)
                                {
                                    if ((bool)dr["TASK_IS_SUMMARY"]) continue;
                                    AddTaskCFs(projGuid, (Guid)dr["TASK_UID"], dsProject.TaskCustomFields, dsProjectUpdate.TaskCustomFields, queueItem.taskLeafsOnly);
                                    if (dsProjectUpdate.TaskCustomFields.Count > queueItem.entityLimit)
                                    {
                                        UpdateProject(sessionGuid, projName, dsProjectUpdate, dsProjectUpdate.TaskCustomFields.Count.ToString() + " task custom fields added to project " + projName + ".");
                                        dsProjectUpdate.TaskCustomFields.Clear();
                                    }
                                }
                            }
                            if (dsProjectUpdate.TaskCustomFields.Count > 0)
                            {
                                UpdateProject(sessionGuid, projName, dsProjectUpdate, dsProjectUpdate.TaskCustomFields.Count.ToString() + " task custom fields added to project " + projName + ".");
                            }
                        }
                        catch (Exception ex)
                        {
                            SetStatus("Adding custom fields failed for project " + projName + ". " + ex.Message, false);
                        }
                        CheckInProject(projGuid, sessionGuid, projName, false);

                        count++;
                    }
                    SetStatus("Project and task custom field creation completed.", true);
                }
                if (queueItem.createResCFs)
                {
                    Guid resGuid;
                    Guid[] resGuids = new Guid[1];
                    string resName;

                    wsResource.ResourceDataSet dsResources = resource.ReadResources("", false);
                    wsResource.ResourceDataSet dsResource;
                    if (dsResources == null)
                    {
                        SetStatus("ReadResources failed in Create Custom Fields.", false);
                        return;
                    }

                    // Sort and filter the projects by name.
                    dsResources.Resources.DefaultView.RowFilter = "RES_NAME like '" + queueItem.resPrefix + "%'";
                    dsResources.Resources.DefaultView.Sort = "RES_NAME";

                    foreach (DataRowView rowRes in dsResources.Resources.DefaultView)
                    {
                        resGuid = (Guid)rowRes["RES_UID"];
                        resName = rowRes["RES_NAME"].ToString();
                        dsResource = resource.ReadResource(resGuid);
                        if (dsResource == null)
                        {
                            SetStatus("ReadResource failed for resource " + resName + ".", false);
                            continue;
                        }

                        CheckOutResource(resGuid, resName);
                        AddResCFs(resGuid, dsResource.ResourceCustomFields, queueItem.resLeafsOnly);
                        UpdateResource(dsResource, resName);
                        CheckInResource(resGuid, resName);
                    }
                    SetStatus("Resource custom field creation completed.", true);
                }
            }
            catch (Exception ex)
            {
                SetStatus(ex.Message, false);
            }
        }

        public void CreateWinProj()
        {
            try
            {
                CreateWinProjItem queueItem = WorkQueues.qCreateWinProj.DequeueItem();

                int count = 0;
                Guid projGuid;
                Guid sessionGuid = Guid.Empty;
                string projName = "";
                long tics = 0;
                Stopwatch timePerOp = new Stopwatch();

                wsProject.ProjectTeamDataSet dsTeam = new wsProject.ProjectTeamDataSet();

                wsProject.ProjectDataSet dsProjects = project.ReadProjectStatus(Guid.Empty, wsProject.DataStoreEnum.WorkingStore, "", (int)PSLib.Project.ProjectType.Project);
                if (dsProjects == null)
                {
                    SetStatus("ReadProjectStatus failed in WinProj.", false);
                    return;
                }

                // Sort and filter the projects by name.
                dsProjects.Project.DefaultView.RowFilter = "PROJ_NAME like '" + queueItem.projectPrefix + "%'";
                dsProjects.Project.DefaultView.Sort = "PROJ_NAME";

                WinProj wp = new WinProj(queueItem.psURL);
                foreach (DataRowView rowProject in dsProjects.Project.DefaultView)
                {
                    try
                    {
                        projName = rowProject["PROJ_NAME"].ToString();
                        projGuid = (Guid)rowProject["PROJ_UID"];

                        timePerOp.Reset();
                        timePerOp.Start();
                        wp.PopulateProject(projName, queueItem.taskPrefix, queueItem.tasksPerProject, queueItem.maxDuration, queueItem.minDuration, 
                                           queueItem.numDigits, queueItem.maxDepDuration, queueItem.minDepDuration, 
                                           queueItem.maxAssignments, queueItem.minAssignments, queueItem.createTaskCFs, queueItem.taskLeafsOnly);
                        timePerOp.Stop();
                        tics = timePerOp.ElapsedMilliseconds / 1000;
                        SetStatus("WinProj processing complete for project " + projName + " in " + tics.ToString() +" seconds.", true);
                    }
                    catch (Exception ex)
                    {
                        SetStatus("WinProj processing failed for project " + projName + ". " + ex.Message, false);
                        continue;
                    }
                    count++;
                }
                wp.Dispose();
                SetStatus("WinProj processing completed.", true);
            }
            catch (Exception ex)
            {
                SetStatus(ex.Message, false);
            }
        }

        public void CreateDeps()
        {
            try
            {
                CreateDependenciesItem queueItem = WorkQueues.qCreateDependencies.DequeueItem();

                DateTime startTime = DateTime.Now;
                int count = 0;
                Guid projGuid;
                string projName;

                wsProject.ProjectDataSet dsProject = new wsProject.ProjectDataSet();
                wsProject.ProjectDataSet dsUpdateProject = new wsProject.ProjectDataSet();
                wsProject.ProjectDataSet dsProjects = project.ReadProjectStatus(Guid.Empty, wsProject.DataStoreEnum.WorkingStore, "", (int)PSLib.Project.ProjectType.Project);
                if (dsProjects == null)
                {
                    SetStatus("ReadProjectStatus failed in Create Dependencies.", false);
                    return;
                }

                DataTable dtLinks = DBUtils.CreateLinkTable();

                // Sort and filter the projects by name.
                dsProjects.Project.DefaultView.RowFilter = "PROJ_NAME like '" + queueItem.projectPrefix + "%'";
                dsProjects.Project.DefaultView.Sort = "PROJ_NAME";
                foreach (DataRowView rowProject in dsProjects.Project.DefaultView)
                {
                    projName = rowProject["PROJ_NAME"].ToString();
                    projGuid = (Guid)rowProject["PROJ_UID"];
                    SetStatus("Reading project " + projName, true);
                    try
                    {
                        dsProject = project.ReadProject(projGuid, wsProject.DataStoreEnum.WorkingStore);
                    }
                    catch (Exception ex)
                    {
                        SetStatus("ReadProject failed on project " + projName + ". " + ex.Message, false);
                        continue;
                    }
                    if (dsProject == null)
                    {
                        SetStatus("ReadProject failed for project " + projName + ".", false);
                        continue;
                    }

                    // Check if dependencies already exists.
                    SetStatus("Project " + projName + " has " + dsProject.Dependency.Count + " dependencies.", true);
                    SetStatus("Project " + projName + " has " + dsProject.Task.Rows.Count + " tasks.", true);

                    if (dsProject.Dependency.Count > 0)
                    {
                        SetStatus("Project " + projName + " skipped.", true);
                        continue;
                    }

                    Guid sessionGuid = Guid.NewGuid();
                    bool ok = CheckOutProject(projGuid, sessionGuid, projName);
                    if (!ok) continue;

                    // Add task dependencies to the project tasks.
                    try
                    {
                        int projectDuration = rnd.Next(queueItem.minDuration, queueItem.maxDuration);
                        int accumaltedDuration;
                        int taskCount;
                        taskCount = 0;
                        dtLinks.Clear();
                        for (int index = 2; index < dsProject.Task.Rows.Count; index++)
                        {
                            accumaltedDuration = 0;
                            while (accumaltedDuration < projectDuration && index < dsProject.Task.Rows.Count)
                            {
                                taskCount++;
                                wsProject.ProjectDataSet.TaskRow theTask = (wsProject.ProjectDataSet.TaskRow)dsProject.Task.Rows[index];
                                wsProject.ProjectDataSet.TaskRow predTask = (wsProject.ProjectDataSet.TaskRow)dsProject.Task.Rows[index - 1];
                                CreateTaskDependency(dsUpdateProject, projGuid, theTask.TASK_UID, predTask.TASK_UID);
                                //SetStatus("Task Dependency: Pred=" + predTask.TASK_NAME + ", Succ=" + theTask.TASK_NAME, true);
                                accumaltedDuration += predTask.TASK_DUR / 4800;
                                index++;
                            }
                            if (taskCount > queueItem.entityLimit)
                            {
                                // Update the project.
                                AddToProject(sessionGuid, projName, dsUpdateProject, "Added " + taskCount.ToString() + " task dependencies to project " + projName + ".");
                                //SetStatus("Added " + taskCount.ToString() + " task dependencies to project " + projName + ".", true);
                                dsUpdateProject.Dependency.Clear();
                            }
                            index++;
                        }
                        // Update the project.
                        AddToProject(sessionGuid, projName, dsUpdateProject, "Added " + taskCount.ToString() + " task dependencies to project " + projName + ".");
                        dsUpdateProject.Dependency.Clear();
                    }
                    catch (Exception ex)
                    {
                        SetStatus("Adding task dependencies failed for project " + projName + ". " + ex.Message, false);
                        break;
                    }

                    CheckInProject(projGuid, sessionGuid, projName, false);

                    count++;
                }
                SetStatus("Task dependency creation completed.", true);
            }
            catch (Exception ex)
            {
                SetStatus(ex.Message, false);
            }
        }

        public void BuildTeam()
        {
            try
            {
                BuildTeamItem queueItem = WorkQueues.qBuildTeam.DequeueItem();

                int count = 0;
                int teamCount = 0;
                int lastResource = 1;
                Guid projGuid;
                Guid sessionGuid = Guid.Empty;
                string projName;
                bool checkedOut = false;

                Hashtable htResourcePool = LoadResources(queueItem.resPrefix);
                wsProject.ProjectTeamDataSet dsTeam = new wsProject.ProjectTeamDataSet();
                wsProject.ProjectDataSet dsUpdateProject = new wsProject.ProjectDataSet();
                wsProject.ProjectDataSet dsUpdateProjectChunk = new wsProject.ProjectDataSet();

                wsProject.ProjectDataSet dsProjects = project.ReadProjectStatus(Guid.Empty, wsProject.DataStoreEnum.WorkingStore, "", (int)PSLib.Project.ProjectType.Project);
                if (dsProjects == null)
                {
                    SetStatus("ReadProjectStatus failed in Build Team.", false);
                    return;
                }

                // Sort and filter the projects by name.
                dsProjects.Project.DefaultView.RowFilter = "PROJ_NAME like '" + queueItem.projectPrefix + "%'";
                dsProjects.Project.DefaultView.Sort = "PROJ_NAME";
                int maxResources = Convert.ToInt32(queueItem.resTeamSize);

                foreach (DataRowView rowProject in dsProjects.Project.DefaultView)
                {
                    dsUpdateProject.Clear();
                    dsTeam.Clear();

                    projName = rowProject["PROJ_NAME"].ToString();
                    projGuid = (Guid)rowProject["PROJ_UID"];

                    try
                    {
                        dsTeam = project.ReadProjectTeam(projGuid);
                    }
                    catch (Exception ex)
                    {
                        SetStatus("ReadProjectTeam failed.  " + ex.Message, false);
                    }
                    teamCount = dsTeam.ProjectTeam.Count;

                    sessionGuid = Guid.NewGuid();
                    if (teamCount < maxResources)
                    {
                        checkedOut = CheckOutProject(projGuid, sessionGuid, projName);
                        if (!checkedOut) continue;

                        BuildTeam(dsTeam, projGuid, maxResources - teamCount, htResourcePool, ref lastResource);
                        SetStatus("Build team completed.  " + dsTeam.ProjectTeam.Rows.Count + " team members added.", true);

                        bool ok = UpdateProjectTeam(projGuid, sessionGuid, projName, dsTeam);
                        if (!ok) continue;

                        CheckInProject(projGuid, sessionGuid, projName, false);
                    }
                    count++;
                }
                SetStatus("Build Team completed.", true);
            }
            catch (Exception ex)
            {
                SetStatus(ex.Message, false);
            }
        }

        public void CreateAssns()
        {
            try
            {
                CreateAssignmentsItem queueItem = WorkQueues.qCreateAssignments.DequeueItem();

                int count = 0;
                int teamCount = 0;
                int lastTeamResource = 1;
                Guid projGuid;
                Guid sessionGuid = Guid.Empty;
                string projName;
                bool checkedOut = false;

                wsProject.ProjectTeamDataSet dsTeam = new wsProject.ProjectTeamDataSet();
                wsProject.ProjectDataSet dsProject;
                wsProject.ProjectDataSet dsUpdateProject = new wsProject.ProjectDataSet();
                wsProject.ProjectDataSet dsUpdateProjectChunk = new wsProject.ProjectDataSet();

                wsProject.ProjectDataSet dsProjects = project.ReadProjectStatus(Guid.Empty, wsProject.DataStoreEnum.WorkingStore, "", (int)PSLib.Project.ProjectType.Project);
                if (dsProjects == null)
                {
                    SetStatus("ReadProjectStatus failed in Create Assignments.", false);
                    return;
                }

                // Sort and filter the projects by name.
                dsProjects.Project.DefaultView.RowFilter = "PROJ_NAME like '" + queueItem.projectPrefix + "%'";
                dsProjects.Project.DefaultView.Sort = "PROJ_NAME";

                foreach (DataRowView rowProject in dsProjects.Project.DefaultView)
                {
                    dsUpdateProject.Clear();
                    dsTeam.Clear();

                    projName = rowProject["PROJ_NAME"].ToString();
                    projGuid = (Guid)rowProject["PROJ_UID"];

                    // Build team for the project.
                    dsProject = project.ReadProject(projGuid, wsProject.DataStoreEnum.WorkingStore);
                    if (dsProject == null)
                    {
                        SetStatus("ReadProject failed for project " + projName + ".", false);
                        continue;
                    }

                    try
                    {
                        dsTeam = project.ReadProjectTeam(projGuid);
                    }
                    catch (Exception ex)
                    {
                        SetStatus("ReadProjectTeam failed.  " + ex.Message, false);
                        continue;
                    }
                    teamCount = dsTeam.ProjectTeam.Count;

                    sessionGuid = Guid.NewGuid();

                    // Add assignments to the tasks.
                    foreach (wsProject.ProjectDataSet.TaskRow theTask in dsProject.Task.Rows)
                    {
                        if (theTask.TASK_IS_SUMMARY) continue;
                        CreateAssignments(dsTeam, dsUpdateProject, projGuid, theTask.TASK_UID, queueItem.maxAssignments, queueItem.minAssignments, ref lastTeamResource);
                    }

                    try
                    {
                        checkedOut = CheckOutProject(projGuid, sessionGuid, projName);
                        if (!checkedOut) continue;

                        // Break the operation up into manageable entity chunks.
                        int maxEntities = queueItem.entityLimit;
                        int assnCount = 0;
                        foreach (wsProject.ProjectDataSet.AssignmentRow rowAssn in dsUpdateProject.Assignment.Rows)
                        {
                            // Copy the row.
                            CopyAssnRow(dsUpdateProjectChunk, rowAssn);
                            assnCount++;
                            // Update the project.
                            if (assnCount >= maxEntities)
                            {
                                AddToProject(sessionGuid, projName, dsUpdateProjectChunk, "Added " + assnCount.ToString() + " assignments to project " + projName + "."); 
                                dsUpdateProjectChunk.Assignment.Clear();
                                assnCount = 0;
                            }
                        }
                        // Final update.
                        AddToProject(sessionGuid, projName, dsUpdateProjectChunk, "Added " + assnCount.ToString() + " assignments to project " + projName + ".");
                        dsUpdateProjectChunk.Assignment.Clear();

                        CheckInProject(projGuid, sessionGuid, projName, false);
                    }
                    catch (Exception ex)
                    {
                        SetStatus("Adding assignments failed for project " + projName + ". " + ex.Message, false);
                        continue;
                    }
                    count++;
                }
                SetStatus("Assignment creation completed.", true);
            }
            catch (Exception ex)
            {
                SetStatus(ex.Message, false);
            }
        }

        public void PublishProjects()
        {
            try
            {
                PublishProjectsItem queueItem = WorkQueues.qPublishProjects.DequeueItem();

                int count = 0;
                Guid projGuid;
                string projName;

                wsProject.ProjectDataSet dsProjects = project.ReadProjectStatus(Guid.Empty, wsProject.DataStoreEnum.WorkingStore, "", (int)PSLib.Project.ProjectType.Project);
                if (dsProjects == null)
                {
                    SetStatus("ReadProjectStatus failed during Publish.", false);
                    return;
                }

                // Sort and filter the projects by name.
                dsProjects.Project.DefaultView.RowFilter = "PROJ_NAME like '" + queueItem.projectPrefix + "%'";
                dsProjects.Project.DefaultView.Sort = "PROJ_NAME";
                foreach (DataRowView rowProject in dsProjects.Project.DefaultView)
                {
                    projName = rowProject["PROJ_NAME"].ToString();
                    projGuid = (Guid)rowProject["PROJ_UID"];

                    PublishProject(projGuid, projName);

                    count++;
                }
                SetStatus("Project publishing completed.", true);
            }
            catch (Exception ex)
            {
                SetStatus(ex.Message, false);
            }
        }
        #endregion

        #region Project Helpers
        public static bool CheckOutProject(Guid projGuid, Guid sessionGuid, string projName)
        {
            Guid jobGuid = Guid.NewGuid();
            SetStatus("Check out project " + projName + ".", true);
            try
            {
                Helper.project.CheckOutProject(projGuid, sessionGuid, "");
                return true;
            }
            catch (Exception ex)
            {
                SetStatus("CheckOutProject failed for project " + projName + ". " + ex.Message, false);
                return false;
            }
        }

        public static bool CheckInProject(Guid projGuid, Guid sessionGuid, string projName, bool waitForQueue)
        {
            Guid jobGuid = Guid.NewGuid();
            SetStatus("Checkin project " + projName + ".", true);
            try
            {
                Helper.project.QueueCheckInProject(jobGuid, projGuid, true, sessionGuid, "Data Pop Tool");
                if (waitForQueue) Helper.WaitForQueue(jobGuid);
                return true;
            }
            catch (Exception ex)
            {
                SetStatus("QueueCheckInProject failed for project " + projName + ". " + ex.Message, false);
                return false;
            }
        }

        public static bool PublishProject(Guid projGuid, string projName)
        {
            Guid jobGuid = Guid.NewGuid();
            SetStatus("Publish project " + projName + ".", true);
            try
            {
                Helper.project.QueuePublish(jobGuid, projGuid, true, "");
                return true;
            }
            catch (Exception ex)
            {
                SetStatus("QueuePublish failed for project " + projName + ". " + ex.Message, false);
                return false;
            }
        }

        public static bool UpdateProjectTeam(Guid projGuid, Guid sessionGuid, string projName, wsProject.ProjectTeamDataSet dsTeam)
        {
            Guid jobGuid = Guid.NewGuid();
            SetStatus("Update project team for project " + projName + ".", true);
            try
            {
                Helper.project.QueueUpdateProjectTeam(jobGuid, sessionGuid, projGuid, dsTeam);
                return true;
            }
            catch (Exception ex)
            {
                SetStatus("QueueUpdateProjectTeam failed for project " + projName + ". " + ex.Message, false);
                return false;
            }
        }
        #endregion

        #region Web Services
        public static wsLogin.LoginWindows login = new wsLogin.LoginWindows();
        public static wsSecurity.Security security = new wsSecurity.Security();
        public static wsResource.Resource resource = new wsResource.Resource();
        public static wsCalendar.Calendar calendar = new wsCalendar.Calendar();
        public static wsProject.Project project = new wsProject.Project();
        public static wsQueue.QueueSystem queue = new wsQueue.QueueSystem();
        public static wsCustomFields.CustomFields customFields = new wsCustomFields.CustomFields();
        public static wsLookup.LookupTable lookup = new wsLookup.LookupTable();
        #endregion

        #region PSI Helpers
        static public bool Login()
        {
            return login.Login();
        }

        static public void Logoff()
        {
            login.Logoff();
        }

        static public void SetWebServiceURLs(string path, ICredentials cc)
        {
            login.Url = (path + "loginWindows.asmx");
            security.Url = (path + "security.asmx");
            resource.Url = (path + "resource.asmx");
            calendar.Url = (path + "calendar.asmx");
            project.Url = (path + "project.asmx");
            queue.Url = (path + "queuesystem.asmx");
            customFields.Url = (path + "customFields.asmx");
            lookup.Url = (path + "lookupTable.asmx");
            login.Credentials = cc;
            security.Credentials = cc;
            resource.Credentials = cc;
            calendar.Credentials = cc;
            project.Credentials = cc;
            queue.Credentials = cc;
            customFields.Credentials = cc;
            lookup.Credentials = cc;
        }

        static public wsCalendar.CalendarDataSet ReadCalendars()
        {
            PSLib.Filter filter = new PSLib.Filter();
            PSLib.Filter.FieldBase field = new PSLib.Filter.Field("Calendars", "CAL_NAME");
            filter.Fields.Add(field);
            field = new PSLib.Filter.Field("Calendars", "CAL_UID");
            filter.Fields.Add(field);
            filter.FilterTableName = "Calendars";
            return calendar.ReadCalendars(filter.GetXml(), false);
        }

        static private void CheckOutResource(Guid resGuid, string resName)
        {
            try
            {
                Guid[] resGuids = new Guid[1];
                resGuids[0] = resGuid;
                resource.CheckOutResources(resGuids);
                SetStatus("Resource " + resName + " checked out.", true);
            }
            catch (Exception ex)
            {
                SetStatus("CheckOutResources failed for resource " + resName + ". " + ex.Message, false);
            }
        }

        static private void UpdateResource(wsResource.ResourceDataSet dsResource, string resName)
        {
            try
            {
                resource.UpdateResources(dsResource, false, false);
                SetStatus("Resource " + resName + " updated.", true);
            }
            catch (Exception ex)
            {
                SetStatus("UpdateResources failed for resource " + resName + ". " + ex.Message, false);
            }
        }
        static private void CheckInResource(Guid resGuid, string resName)
        {
            try
            {
                Guid[] resGuids = new Guid[1];
                resGuids[0] = resGuid;
                resource.CheckInResources(resGuids, true);
                SetStatus("Resource " + resName + " checked in.", true);
            }
            catch (Exception ex)
            {
                SetStatus("CheckInResources failed for resource " + resName + ". " + ex.Message, false);
            }
        }

        #endregion

        #region Create Entities
        static public Guid CreateProject(wsProject.ProjectDataSet dsProject, string projectName, string projectType, string prefix, int digits, int max, int min, string calendar)
        {
            wsProject.ProjectDataSet.ProjectRow projectRow = dsProject.Project.NewProjectRow();
            projectRow.PROJ_UID = Guid.NewGuid();
            projectRow.PROJ_NAME = projectName;
            projectRow.CAL_UID = GetCalendarGuid(calendar);
            projectRow.PROJ_TYPE = (int)Enum.Parse(typeof(PSLib.Project.ProjectType), projectType);
            projectRow.ProjectOwnerID = GetProjectOwnerGuid(prefix, digits, max, min);
            dsProject.Project.AddProjectRow(projectRow);
            return projectRow.PROJ_UID;
        }

        static public Guid CreateTask(wsProject.ProjectDataSet dsProject, Guid projGuid, string taskName, bool isSummary, int max, int min)
        {
            wsProject.ProjectDataSet.TaskRow taskRow = dsProject.Task.NewTaskRow();
            taskRow.PROJ_UID = projGuid;
            taskRow.TASK_UID = Guid.NewGuid();
            taskRow.TASK_NAME = taskName;
            taskRow.TASK_DUR = rnd.Next(min, max) * 4800;
            taskRow.TASK_DUR_FMT = (int)PSLib.Task.DurationFormat.Day;
            taskRow.TASK_IS_SUMMARY = isSummary;
            dsProject.Task.AddTaskRow(taskRow);
            return taskRow.TASK_UID;
        }

        static public int CreateAssignments(wsProject.ProjectTeamDataSet dsTeam, wsProject.ProjectDataSet dsProject, Guid projGuid, Guid taskGuid, int max, int min, ref int lastTeamResource)
        {
            int numAssns = rnd.Next(min, max+1);
            for (int index = 1; index <= numAssns; index++)
            {
                wsProject.ProjectDataSet.AssignmentRow assnRow = (wsProject.ProjectDataSet.AssignmentRow)dsProject.Assignment.NewAssignmentRow();
                assnRow.ASSN_UID = Guid.NewGuid();
                assnRow.RES_UID = GetTeamResource(dsTeam, ref lastTeamResource);
                assnRow.TASK_UID = taskGuid;
                assnRow.PROJ_UID = projGuid;
                dsProject.Assignment.AddAssignmentRow(assnRow);
            }
            return numAssns;
        }

        static public void CreateTaskDependency(wsProject.ProjectDataSet dsProject, Guid projGuid, Guid taskSuccGuid, Guid taskPredGuid)
        {
            wsProject.ProjectDataSet.DependencyRow theDependency = dsProject.Dependency.NewDependencyRow();
            theDependency.LINK_UID = Guid.NewGuid();
            theDependency.LINK_SUCC_UID = taskSuccGuid;
            theDependency.LINK_PRED_UID = taskPredGuid;
            theDependency.PROJ_UID = projGuid;
            dsProject.Dependency.AddDependencyRow(theDependency);
        }

        static private Guid GetProjectOwnerGuid(string prefix, int digits, int max, int min)
        {
            int index = rnd.Next(min, max);
            string resName = prefix + GetDigits(index, digits);

            try
            {
                dsResource.Resources.DefaultView.RowFilter = "RES_NAME = '" + resName + "'";
                return (Guid)dsResource.Resources.DefaultView[0]["RES_UID"];
            }
            catch (Exception)
            {
                return Guid.Empty;
            }
        }

        static private Guid GetCalendarGuid(string calender)
        {
            try
            {
                dsCalendar.Calendars.DefaultView.RowFilter = "CAL_NAME = '" + calender + "'";
                return (Guid)dsCalendar.Calendars.DefaultView[0]["CAL_UID"];
            }
            catch (Exception)
            {
                return Guid.Empty;
            }
        }

        static private Guid GetTeamResource(wsProject.ProjectTeamDataSet dsTeam, ref int lastTeamResource)
        {
            if (dsTeam.ProjectTeam.Rows.Count == 0) return Guid.Empty;
            lastTeamResource++;
            if (lastTeamResource >= dsTeam.ProjectTeam.Rows.Count) lastTeamResource = 0;
            wsProject.ProjectTeamDataSet.ProjectTeamRow row = dsTeam.ProjectTeam[lastTeamResource];
            return row.RES_UID;
        }
        #endregion

        #region Lookup Tree Helpers
        static public DataRowView FindLookupTableTree(Guid ltUid)
        {
            DataView dv = new DataView(dsLookup.LookupTableTrees);
            dv.RowFilter = "LT_UID = '" + ltUid.ToString() + "'";
            if (dv.Count == 0) return null;

            int index = rnd.Next(0, dv.Count);
            return dv[index];
        }

        static public DataRowView FindChildLookupTableTree(Guid ltStructUid)
        {
            DataView dv = new DataView(dsLookup.LookupTableTrees);
            dv.RowFilter = "LT_PARENT_STRUCT_UID = '" + ltStructUid.ToString() + "'";
            if (dv.Count == 0) return null;

            int index = rnd.Next(0, dv.Count);
            return dv[index];
        }
        #endregion

        #region Custom Field Helpers
        static public void AddProjCFs(Guid projUid, wsProject.ProjectDataSet.ProjectCustomFieldsDataTable dtProjCFs, bool leafOnly)
        {
            foreach (wsCustomFields.CustomFieldDataSet.CustomFieldsRow rowCF in dsProjCustomFields.CustomFields.Rows)
            {
                if (!rowCF.IsMD_PROP_FORMULANull()) continue;

                dtProjCFs.DefaultView.RowFilter = "PROJ_UID = '" + projUid.ToString() + "' AND MD_PROP_UID = '" + rowCF.MD_PROP_UID + "'";
                if (dtProjCFs.DefaultView.Count == 0)
                {
                    // Add the custom field.
                    wsProject.ProjectDataSet.ProjectCustomFieldsRow rowProjCF = dtProjCFs.NewProjectCustomFieldsRow();
                    rowProjCF.MD_PROP_UID = rowCF.MD_PROP_UID;
                    rowProjCF.PROJ_UID = projUid;
                    rowProjCF.CUSTOM_FIELD_UID = Guid.NewGuid();
                    switch (rowCF.MD_PROP_TYPE_ENUM)
                    {
                        case (byte)PSLib.CustomField.Type.TEXT:
                            if (!rowCF.IsMD_LOOKUP_TABLE_UIDNull())
                            {
                                DataRowView rowLTT = FindLookupTableTree(rowCF.MD_LOOKUP_TABLE_UID);
                                DataRowView rowLTTLeaf = rowLTT;
                                if (rowLTT != null)
                                {
                                    if (LeafOnly(leafOnly, rowCF))
                                    {
                                        while (rowLTT != null)
                                        {
                                            rowLTTLeaf = rowLTT;
                                            rowLTT = FindChildLookupTableTree((Guid)rowLTT["LT_STRUCT_UID"]);
                                        }
                                    }
                                    rowProjCF.CODE_VALUE = (Guid)rowLTTLeaf["LT_STRUCT_UID"];
                                }
                            }
                            else
                            {
                                rowProjCF.TEXT_VALUE = "Created by Data Population";
                            }
                            break;

                        case (byte)PSLib.CustomField.Type.NUMBER:
                            rowProjCF.NUM_VALUE = 123;
                            break;

                        case (byte)PSLib.CustomField.Type.DATE:
                            rowProjCF.DATE_VALUE = DateTime.Now;
                            break;

                        case (byte)PSLib.CustomField.Type.DURATION:
                            rowProjCF.DUR_VALUE = 45;
                            break;

                        case (byte)PSLib.CustomField.Type.FLAG:
                            rowProjCF.FLAG_VALUE = true;
                            break;

                        case (byte)PSLib.CustomField.Type.COST:
                            rowProjCF.NUM_VALUE = 125;
                            break;

                        default:
                            continue;
                    }
                    dtProjCFs.AddProjectCustomFieldsRow(rowProjCF);
                }
            }
        }
        static public int AddTaskCFs(Guid projUid, Guid taskUid, wsProject.ProjectDataSet.TaskCustomFieldsDataTable dtTaskCFs, wsProject.ProjectDataSet.TaskCustomFieldsDataTable dtTaskUpdateCFs, bool leafOnly)
        {
            int count = 0;
            foreach (wsCustomFields.CustomFieldDataSet.CustomFieldsRow rowCF in dsTaskCustomFields.CustomFields.Rows)
            {
                if (!rowCF.IsMD_PROP_FORMULANull()) continue;

                dtTaskCFs.DefaultView.RowFilter = "TASK_UID = '" + taskUid.ToString() + "' AND MD_PROP_UID = '" + rowCF.MD_PROP_UID + "'";
                if (dtTaskCFs.DefaultView.Count == 0)
                {
                    // Add the custom field.
                    wsProject.ProjectDataSet.TaskCustomFieldsRow rowTaskCF = dtTaskUpdateCFs.NewTaskCustomFieldsRow();
                    rowTaskCF.MD_PROP_UID = rowCF.MD_PROP_UID;
                    rowTaskCF.PROJ_UID = projUid;
                    rowTaskCF.TASK_UID = taskUid;
                    rowTaskCF.CUSTOM_FIELD_UID = Guid.NewGuid();
                    switch (rowCF.MD_PROP_TYPE_ENUM)
                    {
                        case (byte)PSLib.CustomField.Type.TEXT:
                            if (!rowCF.IsMD_LOOKUP_TABLE_UIDNull())
                            {
                                DataRowView rowLTT = FindLookupTableTree(rowCF.MD_LOOKUP_TABLE_UID);
                                DataRowView rowLTTLeaf = rowLTT;
                                if (rowLTT != null)
                                {
                                    if (LeafOnly(leafOnly, rowCF))
                                    {
                                        while (rowLTT != null)
                                        {
                                            rowLTTLeaf = rowLTT;
                                            rowLTT = FindChildLookupTableTree((Guid)rowLTT["LT_STRUCT_UID"]);
                                        }
                                    }
                                    rowTaskCF.CODE_VALUE = (Guid)rowLTTLeaf["LT_STRUCT_UID"];
                                }
                            }
                            else
                            {
                                rowTaskCF.TEXT_VALUE = "Created by Data Population";
                            }
                            break;

                        case (byte)PSLib.CustomField.Type.NUMBER:
                            rowTaskCF.NUM_VALUE = 123;
                            break;

                        case (byte)PSLib.CustomField.Type.DATE:
                            rowTaskCF.DATE_VALUE = DateTime.Now;
                            break;

                        case (byte)PSLib.CustomField.Type.DURATION:
                            rowTaskCF.DUR_VALUE = 45;
                            break;

                        case (byte)PSLib.CustomField.Type.FLAG:
                            rowTaskCF.FLAG_VALUE = true;
                            break;

                        case (byte)PSLib.CustomField.Type.COST:
                            rowTaskCF.NUM_VALUE = 125;
                            break;

                        default:
                            continue;
                    }
                    dtTaskUpdateCFs.AddTaskCustomFieldsRow(rowTaskCF);
                    count++;
                }
            }
            return count;
        }

        static public void AddResCFs(Guid resUid, wsResource.ResourceDataSet.ResourceCustomFieldsDataTable dtResCFs, bool leafOnly)
        {
            foreach (wsCustomFields.CustomFieldDataSet.CustomFieldsRow rowCF in dsResCustomFields.CustomFields.Rows)
            {
                if (!rowCF.IsMD_PROP_FORMULANull()) continue;

                dtResCFs.DefaultView.RowFilter = "RES_UID = '" + resUid.ToString() + "' AND MD_PROP_UID = '" + rowCF.MD_PROP_UID + "'";
                if (dtResCFs.DefaultView.Count == 0)
                {
                    // Add the custom field.
                    wsResource.ResourceDataSet.ResourceCustomFieldsRow rowResCF = dtResCFs.NewResourceCustomFieldsRow();
                    rowResCF.MD_PROP_UID = rowCF.MD_PROP_UID;
                    rowResCF.RES_UID = resUid;
                    rowResCF.CUSTOM_FIELD_UID = Guid.NewGuid();

                    switch (rowCF.MD_PROP_TYPE_ENUM)
                    {
                        case (byte)PSLib.CustomField.Type.TEXT:
                            if (!rowCF.IsMD_LOOKUP_TABLE_UIDNull())
                            {
                                DataRowView rowLTT = FindLookupTableTree(rowCF.MD_LOOKUP_TABLE_UID);
                                DataRowView rowLTTLeaf = rowLTT;
                                if (rowLTT != null)
                                {
                                    if (LeafOnly(leafOnly, rowCF))
                                    {
                                        while (rowLTT != null)
                                        {
                                            rowLTTLeaf = rowLTT;
                                            rowLTT = FindChildLookupTableTree((Guid)rowLTT["LT_STRUCT_UID"]);
                                        }
                                    }
                                    rowResCF.CODE_VALUE = (Guid)rowLTTLeaf["LT_STRUCT_UID"];
                                }
                                else
                                    continue;
                            }
                            else
                            {
                                rowResCF.TEXT_VALUE = "Created by Data Population";
                            }
                            break;

                        case (byte)PSLib.CustomField.Type.NUMBER:
                            rowResCF.NUM_VALUE = 123;
                            break;

                        case (byte)PSLib.CustomField.Type.DATE:
                            rowResCF.DATE_VALUE = DateTime.Now;
                            break;

                        case (byte)PSLib.CustomField.Type.DURATION:
                            rowResCF.DUR_VALUE = 45;
                            break;

                        case (byte)PSLib.CustomField.Type.FLAG:
                            rowResCF.FLAG_VALUE = true;
                            break;

                        case (byte)PSLib.CustomField.Type.COST:
                            rowResCF.NUM_VALUE = 125;
                            break;

                        default:
                            continue;
                    }
                    dtResCFs.AddResourceCustomFieldsRow(rowResCF);
                }
            }
        }

        static public bool LeafOnly(bool leafOnly, wsCustomFields.CustomFieldDataSet.CustomFieldsRow rowCF)
        {
            if (rowCF.IsMD_PROP_IS_LEAF_NODE_ONLYNull()) return false;
            return leafOnly || rowCF.MD_PROP_IS_LEAF_NODE_ONLY;
        }

        static private void AddToProject(Guid sessionGuid, string projName, wsProject.ProjectDataSet dsProject, string msg)
        {
            try
            {
                Guid jobGuid = Guid.NewGuid();
                project.QueueAddToProject(jobGuid, sessionGuid, dsProject, false);
                SetStatus(msg, true);
            }
            catch (Exception ex)
            {
                SetStatus("QueueAddToProject failed on project " + projName + ". " + ex.Message, false);
            }
        }

        static private void UpdateProject(Guid sessionGuid, string projName, wsProject.ProjectDataSet dsProject, string msg)
        {
            try
            {
                Guid jobGuid = Guid.NewGuid();
                project.QueueUpdateProject(jobGuid, sessionGuid, dsProject, false);
                SetStatus(msg, true);
            }
            catch (Exception ex)
            {
                SetStatus("QueueUpdateProject failed on project " + projName + ". " + ex.Message, false);
            }
        }
        #endregion

        #region Resource Helpers
        static public void CopyAssnRow(wsProject.ProjectDataSet dsUpdateProjectChunk, wsProject.ProjectDataSet.AssignmentRow rowAssn)
        {
            wsProject.ProjectDataSet.AssignmentRow newAssnRow = (wsProject.ProjectDataSet.AssignmentRow)dsUpdateProjectChunk.Assignment.NewAssignmentRow();
            newAssnRow.ASSN_UID = rowAssn.ASSN_UID;
            newAssnRow.RES_UID = rowAssn.RES_UID;
            newAssnRow.TASK_UID = rowAssn.TASK_UID;
            newAssnRow.PROJ_UID = rowAssn.PROJ_UID;
            dsUpdateProjectChunk.Assignment.AddAssignmentRow(newAssnRow);
        }


        static public void BuildTeam(wsProject.ProjectTeamDataSet dsTeam, Guid projUid, int maxResources, Hashtable htResourcePool, ref int lastResource)
        {
            for (int count = 0; count < maxResources; count++)
            {
                Guid resUid = GetResource(htResourcePool, ref lastResource);
                wsProject.ProjectTeamDataSet.ProjectTeamRow teamRow = dsTeam.ProjectTeam.NewProjectTeamRow();
                teamRow.PROJ_UID = projUid;
                teamRow.RES_IS_ENTERPRISE_RESOURCE = true;
                teamRow.RES_UID = resUid;
                teamRow.RES_TYPE = (int)PSLib.Resource.Type.WorkResource;
                teamRow.NEW_RES_UID = resUid;
                dsTeam.ProjectTeam.AddProjectTeamRow(teamRow);
            }
        }

        static private Guid GetResource(Hashtable htResourcePool, ref int lastResource)
        {
            if (htResourcePool.Count == 0) return Guid.Empty;
            lastResource++;
            if (lastResource >= htResourcePool.Count) lastResource = 1;
            return (Guid)htResourcePool[lastResource];
        }

        static public Hashtable LoadResources(string prefix)
        {
            // Get a list of resources.
            dsResource = resource.ReadUserList(wsResource.ResourceActiveFilter.Active);
            int resCount = 0;
            Hashtable htResourcePool = new Hashtable();
            DataView dv = new DataView(dsResource.Resources);
            dv.RowFilter = "RES_NAME like '" + prefix + "%'";
            foreach (DataRowView dr in dv)
            {
                resCount++;
                htResourcePool.Add(resCount, dr["RES_UID"]);
            }
            return htResourcePool;
        }

        static public wsResource.ResourceDataSet.ResourcesRow AddResource(string resName, string ntAcct, wsResource.ResourceDataSet dsResource, wsResource.ResourceAuthorizationDataSet dsAuth, bool useNTAuth, string domain)
        {
            wsResource.ResourceDataSet.ResourcesRow rowResource = dsResource.Resources.NewResourcesRow();
            rowResource.RES_UID = Guid.NewGuid();
            rowResource.RES_NAME = resName;
            rowResource.RES_TYPE = 2;
            dsResource.Resources.AddResourcesRow(rowResource);

            string Acct;
            if (useNTAuth)
            {
                Acct = domain + "\\" + ntAcct;
            }
            else
            {
                Acct = "AspNetSqlMembershipProvider:" + resName;
            }
            // This call sets the user NT account info.  Assumes that the username is the same as the NT account name.
            dsAuth.Resources.AddResourcesRow(rowResource.RES_UID, Acct, useNTAuth, false, Guid.NewGuid());

            return rowResource;
        }

        static public void AddSecurityGroups(wsResource.ResourceAuthorizationDataSet dsAuth, wsResource.ResourceDataSet.ResourcesRow rowResource, ArrayList items)
        {
            // Add the selected security groups.
            wsSecurity.SecurityGroupsDataSet dsGroups = security.ReadGroupList();
            DataView dataview = new DataView(dsGroups.SecurityGroups);
            foreach (string group in items)
            {
                // Get the guid for each group selected.
                dataview.RowFilter = dsGroups.SecurityGroups.WSEC_GRP_NAMEColumn.ColumnName + " = '" + group + "'";
                wsSecurity.SecurityGroupsDataSet.SecurityGroupsRow rowSecGrp = (wsSecurity.SecurityGroupsDataSet.SecurityGroupsRow)dataview[0].Row;
                if (rowSecGrp == null) continue;

                // Add group to the resource.
                wsResource.ResourceAuthorizationDataSet.GroupMembershipsRow rowGMNew =
                    dsAuth.GroupMemberships.NewGroupMembershipsRow();
                rowGMNew.RES_UID = rowResource.RES_UID;
                rowGMNew.WSEC_GRP_UID = rowSecGrp.WSEC_GRP_UID;
                dsAuth.GroupMemberships.AddGroupMembershipsRow(rowGMNew);
            }
        }

        static public void AddSecurityCategories(wsResource.ResourceAuthorizationDataSet dsAuth, wsResource.ResourceDataSet.ResourcesRow rowResource, ArrayList items)
        {
            // Add the selected security categories.
            wsSecurity.SecurityCategoriesDataSet dsCategories = security.ReadCategoryList();
            DataView dataview = new DataView(dsCategories.SecurityCategories);
            foreach (string category in items)
            {
                // Get the guid for each category selected.
                dataview.RowFilter = dsCategories.SecurityCategories.WSEC_CAT_NAMEColumn.ColumnName + " = '" + category + "'";
                wsSecurity.SecurityCategoriesDataSet.SecurityCategoriesRow rowSecCat
                    = (wsSecurity.SecurityCategoriesDataSet.SecurityCategoriesRow)dataview[0].Row;
                if (rowSecCat == null) continue;

                // Add category to the resource.
                wsResource.ResourceAuthorizationDataSet.SecurityPrincipleCategoryRelationsRow rowSPCatRel
                    = dsAuth.SecurityPrincipleCategoryRelations.NewSecurityPrincipleCategoryRelationsRow();
                rowSPCatRel.RES_UID = rowResource.RES_UID;
                rowSPCatRel.WSEC_CAT_UID = rowSecCat.WSEC_CAT_UID;
                dsAuth.SecurityPrincipleCategoryRelations.AddSecurityPrincipleCategoryRelationsRow(rowSPCatRel);
            }
        }

        static public string GetResourceFilter(string resPrefix)
        {
            PSLib.Resource.Type[] resourceTypes = new PSLib.Resource.Type[] { PSLib.Resource.Type.WorkResource };

            wsResource.ResourceDataSet dsResource = new wsResource.ResourceDataSet();

            PSLib.Filter resourceFilter = new Microsoft.Office.Project.Server.Library.Filter();
            resourceFilter.FilterTableName = dsResource.Resources.TableName;
            resourceFilter.Fields.Add(new PSLib.Filter.Field(dsResource.Resources.TableName, dsResource.Resources.RES_NAMEColumn.ColumnName, PSLib.Filter.SortOrderTypeEnum.Asc));
            resourceFilter.Fields.Add(new PSLib.Filter.Field(dsResource.Resources.TableName, dsResource.Resources.RES_TYPEColumn.ColumnName, PSLib.Filter.SortOrderTypeEnum.None));

            resourceFilter.Criteria = new PSLib.Filter.FieldOperator(PSLib.Filter.FieldOperationType.Like, dsResource.Resources.RES_NAMEColumn.ColumnName, resPrefix + "%");
            return resourceFilter.GetXml();
        }
        #endregion

        #region Queue Methods
        public static void WaitForQueue(Guid jobId)
        {
            wsQueue.JobState jobState;
            const int QUEUE_WAIT_TIME = 2; // two seconds
            bool jobDone = false;
            string xmlError = string.Empty;
            int wait = 0;

            //Wait for the project to get through the queue
            // - Get the estimated wait time in seconds
            wait = queue.GetJobWaitTime(jobId);

            // - Wait for it
            Thread.Sleep(wait * 1000);
            // - Wait until it is done.

            do
            {
                // - Get the job state
                jobState = queue.GetJobCompletionState(jobId, out xmlError);

                if (jobState == wsQueue.JobState.Success)
                {
                    jobDone = true;
                }
                else
                {
                    if (jobState == wsQueue.JobState.Unknown
                    || jobState == wsQueue.JobState.Failed
                    || jobState == wsQueue.JobState.FailedNotBlocking
                    || jobState == wsQueue.JobState.CorrelationBlocked
                    || jobState == wsQueue.JobState.Canceled)
                    {
                        // If the job failed, error out
                        throw (new ApplicationException("Queue request " + jobState + " for Job ID " + jobId + ".\r\n" + xmlError));
                    }
                    else
                    {
                        Thread.Sleep(QUEUE_WAIT_TIME * 1000);
                    }
                }
            }
            while (!jobDone);
        }
        #endregion

        #region Directory Services Methods
        static public void AddUser(string domain, string userName, string password)
        {
            // Detect if the account is a domain or local.
            DirectoryEntry AD;
            if (domain.Length == 0)
            {
                AD = new DirectoryEntry("WinNT://" + Environment.MachineName + ",computer");
            }
            else
            {
                AD = new DirectoryEntry("WinNT://" + domain);
            }
            DirectoryEntry NewUser = AD.Children.Add(userName, "User");
            NewUser.Invoke("SetPassword", password);
            NewUser.Invoke("Put", new object[] { "Description", "Added for Project Server 2007 testing" });
            NewUser.CommitChanges();
            DirectoryEntry grp;

            grp = AD.Children.Find("Users", "group");
            if (grp != null) grp.Invoke("Add", new object[] { NewUser.Path.ToString() });
        }
        #endregion

        #region Utilities
        static public string GetDigits(int resNum, int numOfDigits)
        {
            string result = resNum.ToString();
            return result.PadLeft(numOfDigits, '0');
        }

        static private void SetStatus(string msg, bool verbose)
        {
            MainForm.delegateSetStatus d = main.SetStatus;
            d(msg, verbose);
        }
        #endregion

        #region Properties
        static public wsCalendar.CalendarDataSet.CalendarsDataTable Calendars
        {
            get { return dsCalendar.Calendars; }
        }

        static public wsResource.ResourceDataSet.ResourcesDataTable Resources
        {
            get { return dsResource.Resources; }
        }

        static public wsLookup.LookupTableDataSet.LookupTablesDataTable Lookups
        {
            get { return dsLookup.LookupTables; }
        }

        static public wsCustomFields.CustomFieldDataSet.CustomFieldsDataTable ProjectCustomFields
        {
            get { return dsProjCustomFields.CustomFields; }
        }

        static public wsCustomFields.CustomFieldDataSet.CustomFieldsDataTable TaskCustomFields
        {
            get { return dsTaskCustomFields.CustomFields; }
        }

        static public int GetNumTaskCFs
        {
            get { return dsTaskCustomFields.CustomFields.Rows.Count; }
        }

        static public wsCustomFields.CustomFieldDataSet.CustomFieldsDataTable ResourceCustomFields
        {
            get { return dsResCustomFields.CustomFields; }
        }
        #endregion
    }
}
